﻿#include "GameObject.h"
#include "VertexData.h"
#include "PixelShader.h"
#include "VertexShader.h"
#include "Graphics.h"

namespace Base {

	int GameObject::s_Id = 0;
	GameObject::GameObject() :
		m_vsShader(nullptr),
		m_psShader(nullptr)
	{
		m_id = ++s_Id;
	}

	void GameObject::ResetBuffer() {
		m_posBuffer.Reset();
		m_normalBuffer.Reset();
		m_colorBuffer.Reset();
		m_texBuffer.Reset();
		m_tangentBuffer.Reset();
		m_indexBuffer.Reset();
		mInstanceBuffer.Reset();
		m_dxInputLayout.Reset();
	}

	void GameObject::SetMesh_Pos(const MeshData& meshData) {
		ResetBuffer();
		auto device = Graphics::GetInstance()->GetDevice();

		// vertex buffer
		D3D11_BUFFER_DESC vbd = {};
		vbd.Usage = D3D11_USAGE_IMMUTABLE;
		vbd.ByteWidth = static_cast<UINT>(sizeof(Vec3) * meshData.m_posVec.size());
		vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
		D3D11_SUBRESOURCE_DATA sd = {};
		sd.pSysMem = meshData.m_posVec.data();
		D_HRESULT(device->CreateBuffer(&vbd, &sd, m_posBuffer.GetAddressOf()));

		// index buffer
		D3D11_BUFFER_DESC ibd = {};
		ibd.Usage = D3D11_USAGE_IMMUTABLE;
		ibd.ByteWidth = static_cast<UINT>(sizeof(unsigned short) * meshData.m_indicesVec.size());
		ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
		sd.pSysMem = meshData.m_indicesVec.data();
		D_HRESULT(device->CreateBuffer(&ibd, &sd, &m_indexBuffer));

		// input 信息
		auto dxVsBlob = m_vsShader->GetDxVsBlob();
		D_HRESULT(device->CreateInputLayout(
			VertexLayout::Layout_Pos,
			1,
			dxVsBlob->GetBufferPointer(),
			dxVsBlob->GetBufferSize(),
			&m_dxInputLayout));

		// 渲染数据
		m_meshDataInput = {};
		m_meshDataInput.pInputLayout = m_dxInputLayout.Get();
		m_meshDataInput.topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
		m_meshDataInput.pVertexBuffers.push_back(m_posBuffer.Get());
		m_meshDataInput.pIndexBuffer = m_indexBuffer.Get();
		m_meshDataInput.strides = { sizeof(Vec3) };
		m_meshDataInput.offsets = { 0 };
		m_meshDataInput.indexCount = static_cast<UINT>(meshData.m_indicesVec.size());
	}

	void GameObject::SetMesh_PosNormal(const MeshData& meshData) {
		ResetBuffer();
		auto device = Graphics::GetInstance()->GetDevice();

		// vertex buffer
		D3D11_BUFFER_DESC vbd = {};
		vbd.Usage = D3D11_USAGE_IMMUTABLE;
		vbd.ByteWidth = static_cast<UINT>(sizeof(Vec3) * meshData.m_posVec.size());
		vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
		D3D11_SUBRESOURCE_DATA sd = {};
		sd.pSysMem = meshData.m_posVec.data();
		D_HRESULT(device->CreateBuffer(&vbd, &sd, m_posBuffer.GetAddressOf()));

		// normal buffer
		vbd.ByteWidth = static_cast<UINT>(sizeof(Vec3)*meshData.m_normalVec.size());
		sd.pSysMem = meshData.m_normalVec.data();
		D_HRESULT(device->CreateBuffer(&vbd, &sd, m_normalBuffer.GetAddressOf()));

		// index buffer
		D3D11_BUFFER_DESC ibd = {};
		ibd.Usage = D3D11_USAGE_IMMUTABLE;
		ibd.ByteWidth = static_cast<UINT>(sizeof(unsigned short) * meshData.m_indicesVec.size());
		ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
		sd.pSysMem = meshData.m_indicesVec.data();
		D_HRESULT(device->CreateBuffer(&ibd, &sd, &m_indexBuffer));

		// input 信息
		auto dxVsBlob = m_vsShader->GetDxVsBlob();
		D_HRESULT(device->CreateInputLayout(
			VertexLayout::Layout_PosNormal,
			2,
			dxVsBlob->GetBufferPointer(),
			dxVsBlob->GetBufferSize(),
			&m_dxInputLayout));

		// 渲染数据
		m_meshDataInput = {};
		m_meshDataInput.pInputLayout = m_dxInputLayout.Get();
		m_meshDataInput.topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
		m_meshDataInput.pVertexBuffers.push_back(m_posBuffer.Get());
		m_meshDataInput.pVertexBuffers.push_back(m_normalBuffer.Get());
		m_meshDataInput.pIndexBuffer = m_indexBuffer.Get();
		m_meshDataInput.strides = { sizeof(Vec3),sizeof(Vec3) };
		m_meshDataInput.offsets = { 0,0 };
		m_meshDataInput.indexCount = static_cast<UINT>(meshData.m_indicesVec.size());
	}


	void GameObject::SetMesh_PosColor(const MeshData& meshData) {
		ResetBuffer();
		auto device = Graphics::GetInstance()->GetDevice();

		// vertex buffer
		D3D11_BUFFER_DESC vbd = {};
		vbd.Usage = D3D11_USAGE_IMMUTABLE;
		vbd.ByteWidth = static_cast<UINT>(sizeof(Vec3) * meshData.m_posVec.size());
		vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
		D3D11_SUBRESOURCE_DATA sd = {};
		sd.pSysMem = meshData.m_posVec.data();
		D_HRESULT(device->CreateBuffer(&vbd, &sd, m_posBuffer.GetAddressOf()));

		// color buffer
		vbd.ByteWidth = static_cast<UINT>(sizeof(Vec4)*meshData.m_colorVec.size());
		sd.pSysMem = meshData.m_colorVec.data();
		D_HRESULT(device->CreateBuffer(&vbd, &sd, m_colorBuffer.GetAddressOf()));

		// index buffer
		D3D11_BUFFER_DESC ibd = {};
		ibd.Usage = D3D11_USAGE_IMMUTABLE;
		ibd.ByteWidth = static_cast<UINT>(sizeof(unsigned short) * meshData.m_indicesVec.size());
		ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
		sd.pSysMem = meshData.m_indicesVec.data();
		D_HRESULT(device->CreateBuffer(&ibd, &sd, &m_indexBuffer));

		// input 信息
		auto dxVsBlob = m_vsShader->GetDxVsBlob();
		D_HRESULT(device->CreateInputLayout(
			VertexLayout::Layout_PosColor,
			2,
			dxVsBlob->GetBufferPointer(),
			dxVsBlob->GetBufferSize(),
			&m_dxInputLayout));

		// 渲染数据
		m_meshDataInput = {};
		m_meshDataInput.pInputLayout = m_dxInputLayout.Get();
		m_meshDataInput.topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
		m_meshDataInput.pVertexBuffers.push_back(m_posBuffer.Get());
		m_meshDataInput.pVertexBuffers.push_back(m_colorBuffer.Get());
		m_meshDataInput.pIndexBuffer = m_indexBuffer.Get();
		m_meshDataInput.strides = { sizeof(Vec3),sizeof(Vec4) };
		m_meshDataInput.offsets = { 0,0 };
		m_meshDataInput.indexCount = static_cast<UINT>(meshData.m_indicesVec.size());
	}

	void GameObject::SetMesh_PosTex(const MeshData& meshData) {
		ResetBuffer();
		auto device = Graphics::GetInstance()->GetDevice();

		// vertex buffer
		D3D11_BUFFER_DESC vbd = {};
		vbd.Usage = D3D11_USAGE_IMMUTABLE;
		vbd.ByteWidth = static_cast<UINT>(sizeof(Vec3) * meshData.m_posVec.size());
		vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
		D3D11_SUBRESOURCE_DATA sd = {};
		sd.pSysMem = meshData.m_posVec.data();
		D_HRESULT(device->CreateBuffer(&vbd, &sd, m_posBuffer.GetAddressOf()));

		// tex buffer
		vbd.ByteWidth = static_cast<UINT>(sizeof(Vec2)*meshData.m_texVec.size());
		sd.pSysMem = meshData.m_texVec.data();
		D_HRESULT(device->CreateBuffer(&vbd, &sd, m_texBuffer.GetAddressOf()));

		// index buffer
		D3D11_BUFFER_DESC ibd = {};
		ibd.Usage = D3D11_USAGE_IMMUTABLE;
		ibd.ByteWidth = static_cast<UINT>(sizeof(unsigned short) * meshData.m_indicesVec.size());
		ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
		sd.pSysMem = meshData.m_indicesVec.data();
		D_HRESULT(device->CreateBuffer(&ibd, &sd, &m_indexBuffer));

		// input 信息
		auto dxVsBlob = m_vsShader->GetDxVsBlob();
		D_HRESULT(device->CreateInputLayout(
			VertexLayout::Layout_PosTex,
			2,
			dxVsBlob->GetBufferPointer(),
			dxVsBlob->GetBufferSize(),
			&m_dxInputLayout));

		// 渲染数据
		m_meshDataInput = {};
		m_meshDataInput.pInputLayout = m_dxInputLayout.Get();
		m_meshDataInput.topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
		m_meshDataInput.pVertexBuffers.push_back(m_posBuffer.Get());
		m_meshDataInput.pVertexBuffers.push_back(m_texBuffer.Get());
		m_meshDataInput.pIndexBuffer = m_indexBuffer.Get();
		m_meshDataInput.strides = { sizeof(Vec3),sizeof(Vec2) };
		m_meshDataInput.offsets = { 0,0 };
		m_meshDataInput.indexCount = static_cast<UINT>(meshData.m_indicesVec.size());
	}

	void GameObject::SetMesh_PosNormalTex(const MeshData& meshData) {
		ResetBuffer();
		auto device = Graphics::GetInstance()->GetDevice();

		// vertex buffer
		D3D11_BUFFER_DESC vbd = {};
		vbd.Usage = D3D11_USAGE_IMMUTABLE;
		vbd.ByteWidth = static_cast<UINT>(sizeof(Vec3) * meshData.m_posVec.size());
		vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
		D3D11_SUBRESOURCE_DATA sd = {};
		sd.pSysMem = meshData.m_posVec.data();
		D_HRESULT(device->CreateBuffer(&vbd, &sd, m_posBuffer.GetAddressOf()));

		// normal buffer
		vbd.ByteWidth = static_cast<UINT>(sizeof(Vec3)*meshData.m_normalVec.size());
		sd.pSysMem = meshData.m_normalVec.data();
		D_HRESULT(device->CreateBuffer(&vbd, &sd, m_normalBuffer.GetAddressOf()));

		// tex buffer
		vbd.ByteWidth = static_cast<UINT>(sizeof(Vec2)*meshData.m_texVec.size());
		sd.pSysMem = meshData.m_texVec.data();
		D_HRESULT(device->CreateBuffer(&vbd, &sd, m_texBuffer.GetAddressOf()));

		// index buffer
		D3D11_BUFFER_DESC ibd = {};
		ibd.Usage = D3D11_USAGE_IMMUTABLE;
		ibd.ByteWidth = static_cast<UINT>(sizeof(unsigned short) * meshData.m_indicesVec.size());
		ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
		sd.pSysMem = meshData.m_indicesVec.data();
		D_HRESULT(device->CreateBuffer(&ibd, &sd, &m_indexBuffer));

		// input 信息
		auto dxVsBlob = m_vsShader->GetDxVsBlob();
		D_HRESULT(device->CreateInputLayout(
			VertexLayout::Layout_PosNormalTex,
			3,
			dxVsBlob->GetBufferPointer(),
			dxVsBlob->GetBufferSize(),
			&m_dxInputLayout));

		// 渲染数据
		m_meshDataInput = {};
		m_meshDataInput.pInputLayout = m_dxInputLayout.Get();
		m_meshDataInput.topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
		m_meshDataInput.pVertexBuffers.push_back(m_posBuffer.Get());
		m_meshDataInput.pVertexBuffers.push_back(m_normalBuffer.Get());
		m_meshDataInput.pVertexBuffers.push_back(m_texBuffer.Get());
		m_meshDataInput.pIndexBuffer = m_indexBuffer.Get();
		m_meshDataInput.strides = { sizeof(Vec3),sizeof(Vec3),sizeof(Vec2) };
		m_meshDataInput.offsets = { 0,0,0 };
		m_meshDataInput.indexCount = static_cast<UINT>(meshData.m_indicesVec.size());
	}

	void GameObject::SetMesh_PosNormalColorTex(const MeshData& meshData) {
		ResetBuffer();
		auto device = Graphics::GetInstance()->GetDevice();

		// vertex buffer
		D3D11_BUFFER_DESC vbd = {};
		vbd.Usage = D3D11_USAGE_IMMUTABLE;
		vbd.ByteWidth = static_cast<UINT>(sizeof(Vec3) * meshData.m_posVec.size());
		vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
		D3D11_SUBRESOURCE_DATA sd = {};
		sd.pSysMem = meshData.m_posVec.data();
		D_HRESULT(device->CreateBuffer(&vbd, &sd, m_posBuffer.GetAddressOf()));

		// normal buffer
		vbd.ByteWidth = static_cast<UINT>(sizeof(Vec3)*meshData.m_normalVec.size());
		sd.pSysMem = meshData.m_normalVec.data();
		D_HRESULT(device->CreateBuffer(&vbd, &sd, m_normalBuffer.GetAddressOf()));

		// color buffer
		vbd.ByteWidth = static_cast<UINT>(sizeof(Vec4)*meshData.m_colorVec.size());
		sd.pSysMem = meshData.m_colorVec.data();
		D_HRESULT(device->CreateBuffer(&vbd, &sd, m_colorBuffer.GetAddressOf()));

		// tex buffer
		vbd.ByteWidth = static_cast<UINT>(sizeof(Vec2)*meshData.m_texVec.size());
		sd.pSysMem = meshData.m_texVec.data();
		D_HRESULT(device->CreateBuffer(&vbd, &sd, m_texBuffer.GetAddressOf()));

		// index buffer
		D3D11_BUFFER_DESC ibd = {};
		ibd.Usage = D3D11_USAGE_IMMUTABLE;
		ibd.ByteWidth = static_cast<UINT>(sizeof(unsigned short) * meshData.m_indicesVec.size());
		ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
		sd.pSysMem = meshData.m_indicesVec.data();
		D_HRESULT(device->CreateBuffer(&ibd, &sd, &m_indexBuffer));

		// input 信息
		auto dxVsBlob = m_vsShader->GetDxVsBlob();
		D_HRESULT(device->CreateInputLayout(
			VertexLayout::Layout_PosNormalColorTex,
			4,
			dxVsBlob->GetBufferPointer(),
			dxVsBlob->GetBufferSize(),
			&m_dxInputLayout));

		// 渲染数据
		m_meshDataInput = {};
		m_meshDataInput.pInputLayout = m_dxInputLayout.Get();
		m_meshDataInput.topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
		m_meshDataInput.pVertexBuffers.push_back(m_posBuffer.Get());
		m_meshDataInput.pVertexBuffers.push_back(m_normalBuffer.Get());
		m_meshDataInput.pVertexBuffers.push_back(m_colorBuffer.Get());
		m_meshDataInput.pVertexBuffers.push_back(m_texBuffer.Get());
		m_meshDataInput.pIndexBuffer = m_indexBuffer.Get();
		m_meshDataInput.strides = { sizeof(Vec3),sizeof(Vec3),sizeof(Vec4),sizeof(Vec2) };
		m_meshDataInput.offsets = { 0,0,0,0 };
		m_meshDataInput.indexCount = static_cast<UINT>(meshData.m_indicesVec.size());
	}

	// 
	void GameObject::SetInstanceMesh_Pos(const MeshData& meshData) {
		ResetBuffer();
		auto device = Graphics::GetInstance()->GetDevice();

		// vertex buffer
		D3D11_BUFFER_DESC vbd = {};
		vbd.Usage = D3D11_USAGE_IMMUTABLE;
		vbd.ByteWidth = static_cast<UINT>(sizeof(Vec3) * meshData.m_posVec.size());
		vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
		D3D11_SUBRESOURCE_DATA sd = {};
		sd.pSysMem = meshData.m_posVec.data();
		D_HRESULT(device->CreateBuffer(&vbd, &sd, m_posBuffer.GetAddressOf()));


		// instance buffer
		// 后面进行调整
		//vbd.Usage = D3D11_USAGE_DYNAMIC;
		//vbd.ByteWidth = 0; // 暂时不分配,后面调整
		//D_HRESULT(device->CreateBuffer(&vbd, nullptr, mInstanceBuffer.GetAddressOf()));

		// index buffer
		D3D11_BUFFER_DESC ibd = {};
		ibd.Usage = D3D11_USAGE_IMMUTABLE;
		ibd.ByteWidth = static_cast<UINT>(sizeof(unsigned short) * meshData.m_indicesVec.size());
		ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
		sd.pSysMem = meshData.m_indicesVec.data();
		D_HRESULT(device->CreateBuffer(&ibd, &sd, &m_indexBuffer));

		// input 信息
		auto dxVsBlob = m_vsShader->GetDxVsBlob();
		D_HRESULT(device->CreateInputLayout(
			VertexLayout::Layout_Instance_Pos,
			5,
			dxVsBlob->GetBufferPointer(),
			dxVsBlob->GetBufferSize(),
			&m_dxInputLayout));

		// 渲染数据
		m_meshDataInput = {};
		m_meshDataInput.pInputLayout = m_dxInputLayout.Get();
		m_meshDataInput.topology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
		m_meshDataInput.pVertexBuffers.push_back(m_posBuffer.Get());
		m_meshDataInput.pVertexBuffers.push_back(nullptr); // 先用 nullptr填充
		m_meshDataInput.pIndexBuffer = m_indexBuffer.Get();
		m_meshDataInput.strides = { sizeof(Vec3),sizeof(Matrix4x4) };
		m_meshDataInput.offsets = { 0,0 };
		m_meshDataInput.indexCount = static_cast<UINT>(meshData.m_indicesVec.size());
	}

	void GameObject::Draw() {
		auto ctx = Graphics::GetInstance()->GetDeviceContext();

		auto& input = m_meshDataInput;
		ctx->IASetInputLayout(input.pInputLayout);
		ctx->IASetPrimitiveTopology(input.topology);
		ctx->IASetVertexBuffers(0,
			static_cast<UINT>(input.pVertexBuffers.size()),
			input.pVertexBuffers.data(),
			input.strides.data(),
			input.offsets.data());
		ctx->IASetIndexBuffer(input.pIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
		ctx->VSSetShader(m_vsShader->GetDxVertexShader(), nullptr, 0);
		ctx->PSSetShader(m_psShader->GetDxPixelShader(), nullptr, 0);
		ctx->DrawIndexed(input.indexCount, 0, 0);
	}

	void GameObject::DrawInstance(const std::vector<std::shared_ptr<Transform>>& transformVec) {

		auto graphics = Graphics::GetInstance();
		auto device = graphics->GetDevice();
		auto ctx = graphics->GetDeviceContext();
		if (mInstanceCount < transformVec.size())
		{
			// 重新设置实例缓冲器大小
			D3D11_BUFFER_DESC vbd = {};
			vbd.Usage = D3D11_USAGE_DYNAMIC;
			vbd.ByteWidth = transformVec.size() * sizeof(Matrix4x4);
			vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
			vbd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
			D_HRESULT(device->CreateBuffer(&vbd, nullptr, mInstanceBuffer.ReleaseAndGetAddressOf()));
			mInstanceCount = transformVec.size();
			m_meshDataInput.pVertexBuffers[1] = mInstanceBuffer.Get();
		}


		// 更新数据
		D3D11_MAPPED_SUBRESOURCE mappedData;
		D_HRESULT(ctx->Map(mInstanceBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedData));

		// 复制数据
		Matrix4x4* iter = reinterpret_cast<Matrix4x4*>(mappedData.pData);
		for (auto& t : transformVec) {
			*iter = t->GetLocalMatrix().Transpose();
			iter++;
		}
		ctx->Unmap(mInstanceBuffer.Get(), 0);


		auto& input = m_meshDataInput;
		ctx->IASetInputLayout(input.pInputLayout);
		ctx->IASetPrimitiveTopology(input.topology);
		ctx->IASetVertexBuffers(0,
			static_cast<UINT>(input.pVertexBuffers.size()),
			input.pVertexBuffers.data(),
			input.strides.data(),
			input.offsets.data());
		ctx->IASetIndexBuffer(input.pIndexBuffer, DXGI_FORMAT_R16_UINT, 0);
		ctx->VSSetShader(m_vsShader->GetDxVertexShader(), nullptr, 0);
		ctx->PSSetShader(m_psShader->GetDxPixelShader(), nullptr, 0);
		ctx->DrawIndexedInstanced(input.indexCount, transformVec.size(), 0, 0, 0);
	}

	void GameObject::SetShader(VertexShader* vsShader, PixelShader* psShader) {
		m_vsShader = vsShader;
		m_psShader = psShader;
	}
}